﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Media.Imaging;
using System.Windows.Threading;
using System.Xml.Serialization;
using Microsoft.Win32;
using Mvvm.Native;

namespace LayoutPlanning.Model.ImmaModels
{
    public class ImmaExportModelLoadSaveService
    {
        public void SaveModelToImma()
        {
        }

        public async Task<Simulation> LoadFile()
        {
            var dialog = new OpenFileDialog();
            dialog.AddExtension = true;
            dialog.Filter = "XML (*.xml)|*.xml";
            dialog.DefaultExt = "xml";


            if (dialog.ShowDialog() ?? false)
            {
                return await Task.Run(() =>
                {
                    try
                    {
                        using (var s = dialog.OpenFile())
                        {
                            var ser = new XmlSerializer(typeof (Simulation));
                            return (Simulation) ser.Deserialize(s);
                        }
                    }
                    catch
                    {
                        Dispatcher.CurrentDispatcher.InvokeAsync(() => MessageBox.Show("Could not open file"));
                        return null;
                    }
                });
            }
            return null;
        }

        public async void SaveToFile(GraficalObject[] ObjectsInPlant, Workorder order, LayoutModel layout)
        {
            var dialog = new SaveFileDialog();
            dialog.AddExtension = true;
            dialog.Filter = "XML (*.xml)|*.xml";
            dialog.DefaultExt = "xml";

            var t = Dispatcher.CurrentDispatcher.InvokeAsync(() => CreateSimulationModel(ObjectsInPlant, order, layout));
            if (dialog.ShowDialog() ?? false)
            {
                using (var s = dialog.OpenFile())
                {
                    SaveAsXML(await t, s);
                }
            }
        }

        public bool SaveAsXML(Simulation sim, Stream xmloutput)
        {
            try
            {
                var ser = new XmlSerializer(typeof (Simulation));
                ser.Serialize(xmloutput, sim);
            }
            catch(Exception )
            {
                return false;
            }
            return true;
        }

        public Simulation CreateSimulationModel(GraficalObject[] ObjectsInPlant, Workorder order, LayoutModel layout)
        {
            var workshop = new Workshop();
            workshop.Width = layout.Width;
            workshop.Height = layout.Height;
            workshop.Name = "Default";
            //Obsticals
            workshop.Grafics = new Grafics()
            {
                PointCloud =
                    new PointCloud[]
                    {
                        new PointCloud()
                        {
                            File = layout.Pointcloud
                        }
                    }
            };
            
                var pp = new List<Workstation>();
                foreach (var obj in ObjectsInPlant.OfType<GraficalObstacle>())
                {
                    pp.Add(new Workstation()
                    {
                        Obstacles = new Obstacle[]
                        {
                            new Obstacle()
                            {
                                Name = Guid.NewGuid().ToString(),
                                Grafics = new Grafics() {Square = new []{new Square() {Width = obj.SizeX, Height = obj.SizeY}}}
                                , Position = new Point(), Rotation = 0
                                
                            }
                        },
                        Position = obj.Position,
                        Width = obj.SizeX,
                        Height = obj.SizeY,
                        Rotation = 0
                    });
                }
                
            
            //Stations
                foreach (var obj in ObjectsInPlant.OfType<Station>())
                {
                    pp.Add(new Workstation()
                    {
                        Machines = new Machine[]
                        {
                            new Machine()
                            {
                                Position = new Point(),
                                Name = obj.Name,
                                ReferencePoints = obj.WorkPositions.Select(t => new ReferencePoint()
                                {
                                    Position = t.Position,
                                    Name = t.Name,
                                    OperationDirection = t.Angle,

                                })
                                    .Union(
                                        obj.GripPositions.Select(
                                            p =>
                                                new ReferencePoint()
                                                {
                                                    Name = p.Name,
                                                    Position = p.Position,
                                                    OperationDirection = p.Angle
                                                }))
                                    .ToArray(),
                                Grafics = new Grafics() {Box = new []{ new Box() {Depth = obj.SizeY, Width = obj.SizeX, Hight = 500}}},
                                Rotation = 0
                            }
                        },
                        Position = obj.Position,
                        Height = obj.SizeY,
                        Width = obj.SizeX,
                        Rotation = obj.Angle,
                    });
                }

            foreach (var obj in ObjectsInPlant.OfType<GraficalStorageSpace>())
            {
                pp.Add(new Workstation()
                {
                    Storages = new Storage[]
                    {
                            new Storage()
                            {
                                Name = Guid.NewGuid().ToString(),
                                Grafics = new Grafics() {Square = new []{new Square() {Width = obj.SizeX, Height = obj.SizeY}}}
                                ,
                                Position = new Point(),
                                ProductRefereces = obj.Products.Select(t=>new ProductReferece() {Ref = t.Name}).ToArray(),
                                ReferencePoints = new ReferencePoint[] {new ReferencePoint() { Name = "Default", OperationDirection = 0, Position = obj.Origo} },
                                Rotation = 0

                            }
                    },
                    Position = obj.Position,
                    Width = obj.SizeX,
                    Height = obj.SizeY,
                    Rotation = obj.Angle
                });
            }

            workshop.Workstations = pp.ToArray();
            
            workshop.Name = "Default";

            //Process
            var process = new Process();
            var instructions = new List<Instruction>();
            if (order.Worktasks.Count > 0)
            {
                instructions.Add(new Instruction()
                {
                    ReferencePoint1 = 
                        order.Worktasks.FirstOrDefault()?.TaskFromStation?.Name + "," +
                        order.Worktasks.FirstOrDefault()?.TaskFromWorkPosition?.Name,
                    ManikinInstruction = "Start",
                    Name = "StartPosition"
                });

                instructions.AddRange(order.Worktasks.Select(ord => new Instruction()
                {
                    ManikinInstruction = ord.TaskType == GeneralTask.WorkTaskType.Walk?"Move":
                    ord.TaskType == GeneralTask.WorkTaskType.Carry?"Carry" : "Work",
                    ReferencePoint1 = ord.TaskToStation?.Name + "," + ord.TaskToWorkPosition?.Name,
                    ReferencePoint2 = String.IsNullOrWhiteSpace(ord.TaskFromStation?.Name)?null:   ord.TaskFromStation?.Name + "," + ord.TaskFromWorkPosition?.Name,
                    Name = ord.TaskName,
                    TimeSpanType = ord.TaskTime, ProductReference = new ProductReferece() {Ref =  ord.TaskCarryObject?.Name},
                }));
                process.Instructions = instructions.ToArray();
            }

            var sim = new Simulation();
            sim.Plant = new Plant();
            sim.Plant.Workshops = new Workshop[1] {workshop};
            sim.Experiments = new Process[] { process};

            return sim;
        }
    }
}